
#include "SDL.h"
#include "SDL_ttf.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "chunks/GuacImage_rendertext_setup.h"
#include "shared_setup.h"
#include "guacimage.h"

static int raw_open_font(lua_State *L)
{
    SDL_RWops* rw = GuacResourceRWops(L,1);
    TTF_Font* font = TTF_OpenFontIndexRW(rw, 1, lua_tointeger(L,2), luaL_optint(L,3,0));
    if (font == NULL)
        return luaL_error(L, "sdl_ttf error: %s", TTF_GetError());
    TTF_Font** pfont = (TTF_Font**)lua_newuserdata(L, sizeof(TTF_Font*));
    *pfont = font;
    return 1;
}

static int raw_destroy_font(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    TTF_CloseFont(font);
    return 0;
}

static int raw_font_summary(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushfstring(L, "font: \"%s\"", TTF_FontFaceFamilyName(font));
    return 1;
}

static int raw_get_bold(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushboolean(L, TTF_GetFontStyle(font) & TTF_STYLE_BOLD);
    return 1;
}

static int raw_set_bold(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    if (lua_toboolean(L,2))
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) | TTF_STYLE_BOLD);
    else
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) & ~TTF_STYLE_BOLD);
    return 0;
}

static int raw_get_italic(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushboolean(L, TTF_GetFontStyle(font) & TTF_STYLE_ITALIC);
    return 1;
}

static int raw_set_italic(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    if (lua_toboolean(L,2))
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) | TTF_STYLE_ITALIC);
    else
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) & ~TTF_STYLE_ITALIC);
    return 0;
}

static int raw_get_underline(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushboolean(L, TTF_GetFontStyle(font) & TTF_STYLE_UNDERLINE);
    return 1;
}

static int raw_set_underline(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    if (lua_toboolean(L,2))
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) | TTF_STYLE_UNDERLINE);
    else
        TTF_SetFontStyle(font, TTF_GetFontStyle(font) & ~TTF_STYLE_UNDERLINE);
    return 0;
}

static int raw_font_solid(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    SDL_Color col = {luaL_optint(L,3,255), luaL_optint(L,4,255), luaL_optint(L,5,255)};
    SDL_Surface* rendered = TTF_RenderText_Solid(font, luaL_checkstring(L,2), col);
    if (rendered == NULL)
        return luaL_error(L, TTF_GetError());
    GuacImage* img = (GuacImage*)lua_newuserdata(L, sizeof(GuacImage));
    img->surf = rendered;
    img->prect = NULL;
    img->flags = 0;
    img->handle_x = img->handle_y = 0;
    return 1;
}

static int raw_font_shaded(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    SDL_Color fg = {luaL_optint(L,3,255), luaL_optint(L,4,255), luaL_optint(L,5,255)};
    SDL_Color bg = {luaL_optint(L,6,0), luaL_optint(L,7,0), luaL_optint(L,7,0)};
    SDL_Surface* rendered = TTF_RenderText_Shaded(font, luaL_checkstring(L,2), fg, bg);
    if (rendered == NULL)
        return luaL_error(L, TTF_GetError());
    GuacImage* img = (GuacImage*)lua_newuserdata(L, sizeof(GuacImage));
    img->flags = 0;
    img->handle_x = img->handle_y = 0;
    img->surf = rendered;
    img->prect = NULL;
    return 1;
}

static int raw_font_blended(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    SDL_Color col = {luaL_optint(L,3,255), luaL_optint(L,4,255), luaL_optint(L,5,255)};
    SDL_Surface* rendered = TTF_RenderText_Blended(font, luaL_checkstring(L,2), col);
    if (rendered == NULL)
        return luaL_error(L, TTF_GetError());
    GuacImage* img = (GuacImage*)lua_newuserdata(L, sizeof(GuacImage));
    img->surf = rendered;
    img->prect = NULL;
    img->flags = 0;
    img->handle_x = img->handle_y = 0;
    return 1;
}

static int raw_get_height(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushinteger(L, TTF_FontHeight(font));
    return 1;
}

static int raw_get_ascent(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushinteger(L, TTF_FontAscent(font));
    return 1;
}

static int raw_get_descent(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushinteger(L, TTF_FontDescent(font));
    return 1;
}

static int raw_get_lineskip(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushinteger(L, TTF_FontLineSkip(font));
    return 1;
}

static int raw_get_monospace(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushboolean(L, TTF_FontFaceIsFixedWidth(font));
    return 1;
}

static int raw_get_title(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    lua_pushstring(L, TTF_FontFaceFamilyName(font));
    return 1;
}

static int raw_charmatrics(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    luaL_argcheck(L, (lua_type(L,2)==LUA_TSTRING) || (lua_objlen(L,2)==1), 2,
        "expecting a one-character string");
    Uint16 ch = (Uint16)(lua_tostring(L,1)[0]);
    int minx,miny,maxx,maxy,advance;
    TTF_GlyphMetrics(font, ch, &minx,&maxx,&miny,&maxy,&advance);
    lua_pushinteger(L, minx);
    lua_pushinteger(L, miny);
    lua_pushinteger(L, maxx);
    lua_pushinteger(L, maxy);
    lua_pushinteger(L, advance);
    return 5;
}

static int raw_textsize(lua_State *L)
{
    TTF_Font* font = *(TTF_Font**)lua_touserdata(L,1);
    int w,h;
    TTF_SizeText(font, luaL_checkstring(L,2), &w,&h);
    lua_pushinteger(L,w);
    lua_pushinteger(L,h);
    return 2;
}

static luaL_reg raw_rendertext_functions[] = {
    {"open_font", raw_open_font},
    {"destroy_font", raw_destroy_font},
    {"font_summary", raw_font_summary},
    {"render_solid", raw_font_solid},
    {"render_shaded", raw_font_shaded},
    {"render_blended", raw_font_blended},
    {"get_bold", raw_get_bold},
    {"set_bold", raw_set_bold},
    {"get_italic", raw_get_italic},
    {"set_italic", raw_set_italic},
    {"get_underline", raw_get_underline},
    {"set_underline", raw_set_underline},
    {"get_height", raw_get_height},
    {"get_ascent", raw_get_ascent},
    {"get_descent", raw_get_descent},
    {"get_lineskip", raw_get_lineskip},
    {"get_monospace", raw_get_monospace},
    {"get_title", raw_get_title},
    {"charmetrics", raw_charmatrics},
    {"textsize", raw_textsize},

    {"setmetatable", raw_setmetatable},
    {"getmetatable", raw_getmetatable},
    {"setfenv", raw_setfenv},
    {"getfenv", raw_getfenv},
    {NULL,NULL}
};

int luaopen_font(lua_State *L)
{
    if (!TTF_WasInit() && TTF_Init() == -1)
        return luaL_error(L, TTF_GetError());

    lua_getglobal(L, "require");
    lua_pushliteral(L, "image");
    lua_call(L,1,0);

    lua_newtable(L);
    luaL_register(L, NULL, raw_rendertext_functions);
    lua_pushvalue(L, LUA_REGISTRYINDEX);
    lua_setfield(L, -2, "registry");
    luaL_loadbuffer(L, chunk_GuacImage_rendertext_setup, sizeof(chunk_GuacImage_rendertext_setup), NULL);
    lua_insert(L,-2);
    lua_call(L,1,1);

    lua_pushvalue(L,-1);
    lua_setglobal(L,"font");

    return 1;
}
